/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package core;


/**
 *
 * @author victor
 */
public class HTMLCleaner {
    private String document;
    
    public HTMLCleaner(String document){
        this.document=document;
        removeLineBreaks();
        removeComments();
    }
    private void removeLineBreaks(){
        document=document.replaceAll("\n", " ");
    }
    private void removeHTMLCode(String tag){
        document=document.replaceAll(tag, "");
    }
    private void replaceHTMLCode(String beforeTag,String afterAttribute){
        document=document.replaceAll(beforeTag, afterAttribute);
    }
    private void insertLineBreaks(){
        StringBuilder sB=new StringBuilder();
        int lastTime=0;
        while(lastTime<document.length()&&document.indexOf("</",lastTime)!=-1){
            int tagBegin=document.indexOf("</",lastTime);
            int tagEnd=document.indexOf(">",tagBegin+2);
            sB.append(document.substring(lastTime, tagEnd+1));
            sB.append("\n");
            lastTime=tagEnd+1;
        }
        sB.append(document.substring(lastTime));
        
        document=sB.toString();
    }
    private void removeComments(){
        
        //char[] charHtmlTemp=html.toCharArray();
        while(document.indexOf("<!--")!=-1){
            int beginOfCommentPosition=document.indexOf("<!--");
            int endOfCommentPosition=document.indexOf("-->");
            if(endOfCommentPosition==-1) throw new RuntimeException("One of the comments is not closed.");
            String commentToRemove=document.substring(beginOfCommentPosition, endOfCommentPosition+3);
            document=document.replace(commentToRemove, "");
        }
        
    }
    /**
     * Allows to encapsulate a serie of the given tag by an other tag. For example, for a serie of <li> tags that are not surrounded by <ul> tags, the function will add <ul> at the beginning and </ul> at the end.
     * @param tagToEncapsulate
     * @param encapsulatingTag
     */
    private void encapsulateSerieOfTags(String tagToEncapsulate,String encapsulatingTag){
        if(!document.contains("<"+tagToEncapsulate)) return;
        int lastTime=0;
        StringBuilder sb=new StringBuilder();
        char[] charTab=document.toCharArray();
        while(lastTime<document.length()&&(document.substring(lastTime).contains("<"+tagToEncapsulate)||document.substring(lastTime).contains("<"+encapsulatingTag))){
            if(document.substring(lastTime).contains("<"+encapsulatingTag)&&document.indexOf("<"+encapsulatingTag, lastTime)<document.indexOf("<"+tagToEncapsulate, lastTime)){
                int beginList=document.indexOf("<"+encapsulatingTag, lastTime);
                int endList=document.indexOf("</"+encapsulatingTag, lastTime);
                int temp=document.indexOf("<"+encapsulatingTag, lastTime+1);
                while(temp!=-1&&temp<endList&&document.indexOf("</"+encapsulatingTag,endList+1)!=-1){
                    endList=document.indexOf("</"+encapsulatingTag,endList+1);
                    temp=document.indexOf("<"+encapsulatingTag,temp+1);
                }
                if(endList==-1) throw new RuntimeException("A <"+encapsulatingTag+"> is not correctly closed. No solution yet.");
                sb.append(document.substring(lastTime,endList+2+encapsulatingTag.length()+1));
                lastTime=endList+2+encapsulatingTag.length()+1;
            }
            else{
                int listBegin=document.indexOf("<"+tagToEncapsulate, lastTime);
                int listEnd=document.indexOf("</"+tagToEncapsulate,listBegin)+(2+tagToEncapsulate.length());
//                while(document.indexOf("</"+tagToEncapsulate+">", listEnd)!=-1&&document.substring(listEnd+1).indexOf("<"+tagToEncapsulate)==0){
//
//                    listEnd=document.indexOf("</"+tagToEncapsulate+">", listEnd)+(2+tagToEncapsulate.length());
//                }
                while(document.indexOf("</"+tagToEncapsulate+">", listEnd)!=-1){
                    int i=1;
                    while(charTab[i+listEnd]==' ') i++;
                    if(document.indexOf("<"+tagToEncapsulate,listEnd+i)==listEnd+i){
                        listEnd=document.indexOf("</"+tagToEncapsulate,listEnd+i)+(2+tagToEncapsulate.length());
                    }
                    else break;
                }
                sb.append(document.substring(lastTime,listBegin));
                sb.append("<").append(encapsulatingTag).append(">");
                sb.append(document.substring(listBegin,listEnd+1));
                sb.append("</").append(encapsulatingTag).append(">");
                lastTime=listEnd+1;
            }
            
        }
        if(lastTime<document.length()){
        sb.append(document.substring(lastTime,document.length()));}
        document=sb.toString();
    }
    private void removeAttributeFromTag(String tag,String attribute){
        if(tag==null || tag.equals("")||attribute==null||attribute.equals("")) return;
        StringBuilder sb=new StringBuilder();
        int lastTime=0;
        while(document.substring(lastTime).contains(attribute+"=")&&document.substring(lastTime).contains("<"+tag)){
            int tagLoc=document.indexOf("<"+tag, lastTime);
            int tagB=tagLoc;
            int tagE=tagB;
            while(document.charAt(tagE)!='>'){
                tagE++;
            }
            if(document.substring(tagB+1,tagE).contains(attribute+"=")){
                int attLocB=document.indexOf(attribute+"=", tagB+1);
                char delim=document.charAt(attLocB+attribute.length()+1);
                int attLocE=attLocB+attribute.length()+2;
                if(delim=='\''||delim=='\"'){
                }

                else{
                    delim=' ';
                }
                while(document.charAt(attLocE)!=delim) attLocE++;
                sb.append(document.substring(lastTime,attLocB));
                sb.append(document.substring(attLocE+1,tagE+1));
            }
            else{
                sb.append(document.substring(lastTime, tagE+1));
            }
            lastTime=tagE+1;
        }
        sb.append(document.substring(lastTime,document.length()));
        document=sb.toString();
    }
    private void removeAttribute(String attribute){
        if(attribute==null||attribute.equals("")) return;
        StringBuilder sb=new StringBuilder();
        int lastTime=0;
        while(document.substring(lastTime).contains(attribute+"=")){
            int attLocB=document.indexOf(attribute+"=", lastTime);
            char delim=document.charAt(attLocB+attribute.length()+1);
            int attLocE=attLocB+attribute.length()+2;
            int lastTimeTemp;
            if(delim=='\''||delim=='\"'){
                while(document.charAt(attLocE)!=delim) attLocE++;
                lastTimeTemp=attLocE+1;
            }
            else{
                while(document.charAt(attLocE)!=' '&&document.charAt(attLocE)!='>') attLocE++;
                lastTimeTemp=attLocE;
            }
            
            sb.append(document.substring(lastTime,attLocB));
            lastTime=lastTimeTemp;
        }
        sb.append(document.substring(lastTime,document.length()));
        document=sb.toString();
    }
    private void removeTag(final String tag){
        String htmlTemp=document;
        if(htmlTemp.contains("<"+tag)||htmlTemp.contains("</"+tag)){
            htmlTemp=htmlTemp.replaceAll("</"+tag+">", "");
            char[] vChar=htmlTemp.toCharArray();
            int globalCharIterator=0;
            while(globalCharIterator<vChar.length){
                if(vChar[globalCharIterator]=='<'){
                    int endOfTag=globalCharIterator+1;
                    while((vChar[endOfTag]!=' '&&vChar[endOfTag]!='>')){
                        endOfTag++;
                    }
                    endOfTag--;
                    String tagTemp=new String(vChar, globalCharIterator+1, endOfTag-globalCharIterator);
                    endOfTag=globalCharIterator;
                        while(vChar[endOfTag]!='>'){
                            endOfTag++;
                        }
                    if(endOfTag==vChar.length) endOfTag--;
                    if(tagTemp.equals(tag)){
                        //endOfTag=(endOfTag-globalCharIterator)+globalCharIterator;

                        String stringToReplace=new String(vChar, globalCharIterator, endOfTag-globalCharIterator+1);
                        htmlTemp=htmlTemp.replaceAll(stringToReplace, "");
                        globalCharIterator=(endOfTag-globalCharIterator)+globalCharIterator+1;
                    }
                    else globalCharIterator=(endOfTag-globalCharIterator)+globalCharIterator+1;
                }
                else globalCharIterator++;
            }

        }
        document=htmlTemp;
    }
    public String getDocument(){
        insertLineBreaks();
        return document;
    }
    public void setDocument(String document){
        this.document=document;
        removeLineBreaks();
    }
    private void tagCorrection(String tagToReplace,String className){
        if(className==null || className.equals("")) return;
        String[] stringsToSearch=new String[]{("class=\""+className),("class="+className),("class=\'"+className)};
        StringBuilder sb=new StringBuilder();
        int lastTime=0;
        while(oneIsInTheDocument(stringsToSearch,lastTime)){
            String stringToSearch=theStringThatComesFirst(stringsToSearch,lastTime);
            int classLoc=document.indexOf(stringToSearch,lastTime);
            int bTagBLoc=classLoc;
            while(document.charAt(bTagBLoc)!='<'){
                bTagBLoc--;
            }
            int bTagELoc=classLoc;
            while(document.charAt(bTagELoc)!='>'){
                bTagELoc++;
            }
            int tagFinder=bTagBLoc+1;
            while(document.charAt(tagFinder)!=' '){
                tagFinder++;
            }
            String tempTag=document.substring(bTagBLoc+1, tagFinder);
            sb.append(document.substring(lastTime, bTagBLoc));
            sb.append("<").append(tagToReplace).append(">");
            String closingTag="</"+tempTag+">";
            sb.append(document.substring(bTagELoc+1,document.indexOf(closingTag, bTagELoc+1))); // Ajout du contenu entre balises.
            sb.append("</").append(tagToReplace).append(">");
            lastTime=document.indexOf(closingTag, bTagELoc+1)+closingTag.length();
        }
        sb.append(document.substring(lastTime, document.length()));
        document=sb.toString();
    }
    private void suppressAttributeInStyleAttribute(String attribute){
        if(attribute==null || attribute.equals("")) return;
        StringBuilder sb=new StringBuilder();
        int lastTime=0;
        while(document.substring(lastTime).contains(attribute+":")&&document.substring(lastTime).contains("style=")){
            int styleLoc=document.indexOf("style=", lastTime);
            int styleB=styleLoc+6; // Position après le = de style=
            char styleDelim=document.charAt(styleB); // Délimiteur de l'attribut style
            int styleE=styleB+1;
            while(document.charAt(styleE)!=styleDelim) styleE++;
            if(document.substring(styleB+1, styleE).contains(attribute+":")){
                int attLocB=document.indexOf(attribute+":", styleB+1);
                int attLocE=attLocB+1;
                while(document.charAt(attLocE)!=';'&&document.charAt(attLocE)!=styleDelim){
                    attLocE++;
                }
                if(document.charAt(attLocE)==';'){
                    attLocE++; // Si le caractère rencontré est le délimiteur de l'attribut style on recule d'un caractère

                }
                sb.append(document.substring(lastTime, attLocB));
                sb.append(document.substring(attLocE, styleE+1));
                
            }
            else{
                sb.append(document.substring(lastTime, styleE+1));
                
            }
            lastTime=styleE+1;
        }
        sb.append(document.substring(lastTime,document.length()));
        document=sb.toString();
    }
    private void correctTitles(String titleClassName){
        if(titleClassName==null || titleClassName.equals("")) return;
        String[] stringsToSearch=new String[]{("class=\""+titleClassName),("class="+titleClassName),("class=\'"+titleClassName)};
        StringBuilder sb=new StringBuilder();
        int lastTime=0;
        while(oneIsInTheDocument(stringsToSearch,lastTime)){
            String stringToSearch=theStringThatComesFirst(stringsToSearch,lastTime);
            int classLoc=document.indexOf(stringToSearch,lastTime);
            int bTagBLoc=classLoc;
            while(document.charAt(bTagBLoc)!='<'){
                bTagBLoc--;
            }
            int bTagELoc=classLoc;
            while(document.charAt(bTagELoc)!='>'){
                bTagELoc++;
            }
            char titleImportanceChar=document.charAt(classLoc+stringToSearch.length());
            int titleImportance=0;
            try{
                titleImportance=Integer.valueOf(String.valueOf(titleImportanceChar));
            }
            catch(NumberFormatException e){
                System.out.println("Error in correctTitles : there is no number after "+stringToSearch+" at least once in the document.\nThe error occurs in the string "+document.substring(classLoc, 100));
            }
            int tagFinder=bTagBLoc+1;
            while(document.charAt(tagFinder)!=' '){
                tagFinder++;
            }
            String tempTag=document.substring(bTagBLoc+1, tagFinder);
            sb.append(document.substring(lastTime, bTagBLoc));
            sb.append("<h").append(titleImportance).append(">");
            String closingTag="</"+tempTag+">";
            sb.append(document.substring(bTagELoc+1,document.indexOf(closingTag, bTagELoc+1))); // Ajout du contenu entre balises.
            sb.append("</h").append(titleImportance).append(">");
            lastTime=document.indexOf(closingTag, bTagELoc+1)+closingTag.length();
        }
        sb.append(document.substring(lastTime, document.length()));
        document=sb.toString();
    }
    private boolean oneIsInTheDocument(String[] array,int beginPosition){
        for(String s:array){
            if(document.substring(beginPosition).contains(s)){
                return true;
            }
        }
        return false;
    }
    private String theStringThatComesFirst(String[] array, int beginPosition){
        int position=0;
        int index=0;
        for(int i=0;i<array.length;i++){
            if(document.substring(beginPosition).indexOf(array[i])!=-1){
                position=document.substring(beginPosition).indexOf(array[i]);
                index=i;
                break;
            }
        }
        
        for(int i=0;i<array.length;i++){
            if(position>document.substring(beginPosition).indexOf(array[i]) && document.substring(beginPosition).indexOf(array[i])!=-1){
                position=document.substring(beginPosition).indexOf(array[i]);
                index=i;
            }
        }
        return array[index];
    }
    public void executes(Setting s){
        switch(s.getType()){
            case ENCAPSULATE_TAGS:
                this.encapsulateSerieOfTags(s.getParam1(),s.getParam1());
                break;
            case SUPPRESS_ATTRIBUTE_IN_STYLE_ATTRIBUTE:
                this.suppressAttributeInStyleAttribute(s.getParam1());
                break;
            case REMOVE_TAG:
                this.removeTag(s.getParam1());
                break;
            case REMOVE_ATTRIBUTE_FROM_TAG:
                this.removeAttributeFromTag(s.getParam1(),s.getParam2());
                break;
            case REMOVE_ATTRIBUTE:
                this.removeAttribute(s.getParam1());
                break;
            case CORRECT_TITLES:
                this.correctTitles(s.getParam1());
                break;
            case CORRECT_TAG:
                this.tagCorrection(s.getParam1(), s.getParam2());
                break;
            case REMOVE_CODE:
                this.removeHTMLCode(s.getParam1());
                break;
            case REPLACE_CODE:
            case REPLACE_IMAGE_PATH:
                this.replaceHTMLCode(s.getParam1(), s.getParam2());
                break;
        }
    }
}

